const BaseService = require('./BaseService');
const UserDao = require('../dao/UserDao');
const blockAuditDao = require('../dao/BlockAuditDao');
const BusinessExceptionProxy = require('../exception/BusinessExceptionProxy');
const CashRecord = require('../model/CashRecord');
const { CashAction, CashActionStatus } = require('../constants/DbEnum');

/**
 * @author thomas.kang@hrx.ai
 * @module service/user
 */
class UserService extends BaseService {
  /**
   * constructor
   */
  constructor() {
    super(UserDao);
  }

  /**
   * @param {user} user
   * @param {String} user.username
   * @return {Promise<UrlPattern|fields.balance|{type, allowNull, defaultValue}|balance>}
   */
  async getBalance(user) {
    let me = this;
    let existedUser = await me.findUser(user);
    return existedUser.balance;
  }

  async findUser(user) {
    let me = this;
    let existedUser = await me.dao.findOne(user);
    if (!existedUser) {
      BusinessExceptionProxy.userNotExisted(user.username);
    }
    return existedUser;
  }

  async submitPhoto(user, photo, type) {
    let me = this;
    if (!photo) {
      BusinessExceptionProxy.requiredAndNotNull('photo');
    }
    let existedUser = await me.findUser(user);
    let typeLower = type ? type.toString().toLocaleLowerCase() : '';
    switch (typeLower) {
      case 'passport':
        await existedUser.update({ passportPhoto: photo });
        break;
      case 'bill':
        await existedUser.update({ billPhoto: photo });
        break;
      default:
        BusinessExceptionProxy.unSupportType(type);
        break;
    }
  }

  async submitUserInfo(updatedUser) {
    let me = this;
    let userNamePair = { username: updatedUser.username };
    let userExisted = await me.dao.findOne(userNamePair);
    try {
      if (userExisted) {
        Object.assign(userExisted, updatedUser);
        await userExisted.update(userExisted.get());
        console.log('userExisted,updated user', updatedUser);
      } else {
        //create user
        console.log('create User', updatedUser);
        await me.dao.create(updatedUser);
      }
    } catch (e) {
      console.log(e);
      let errorItem = [];
      e.errors.forEach((item) => {
        errorItem.push({ path: item.path, type: item.type });
      });
      BusinessExceptionProxy.parameterValueError(errorItem);
    }
  }

  /**
   * depositCash
   * @param {String} username
   * @param {Decimal} amount
   * @return {Promise<void>}
   */
  async depositCash(username, amount) {
    return this.changeCash(CashAction.DEPOSIT, username, amount);
  }

  /**
   * withdrawCash
   * @param {String} username
   * @param {Decimal} amount
   * @return {Promise<void>}
   */
  async withdrawCash(username, amount) {
    if (await blockAuditDao.isBlocking(username)) {
      BusinessExceptionProxy.blockingUser();
    }

    return this.changeCash(CashAction.WITHDRAW, username, amount);
  }

  /**
   * changeCash
   * @param {String} action
   * @param {String} username
   * @param {Decimal} amount
   * @return {Promise<void>}
   */
  async changeCash(action, username, amount) {
    const user = await this.findOne({ username });

    if (!user) {
      BusinessExceptionProxy.userNotExisted(username);
    }

    const beforeBalance = user.balance;

    if ((action = CashAction.DEPOSIT)) {
      user.balance += amount;
    } else {
      user.balance -= amount;
    }

    const newRecord = {
      username,
      action,
      amount,
      beforeBalance,
      afterBalance: user.balance,
      paymentInfo: 'mock bank card',
      status: CashActionStatus.COMPLETED,
    };

    return this.transaction((t) => {
      return Promise.all([user.update(user.get()), CashRecord.create(newRecord)]);
    });
  }
}

module.exports = new UserService();
